Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
PolymorphicEntityStrategy
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
6 / 6
26
100.00% covered (success)
100.00%
1 / 1
 supports
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModificationMetadata
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
7
 getCreationMetadata
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
7
 getResultMetadata
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
7
 mergeChildClass
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2namespace Apie\Core\Metadata\Strategy;
3
4use Apie\Core\Context\ApieContext;
5use Apie\Core\Context\MetadataFieldHashmap;
6use Apie\Core\Entities\PolymorphicEntityInterface;
7use Apie\Core\Metadata\CompositeMetadata;
8use Apie\Core\Metadata\Fields\DiscriminatorColumn;
9use Apie\Core\Metadata\Fields\OptionalField;
10use Apie\Core\Metadata\StrategyInterface;
11use Apie\Core\Other\DiscriminatorConfig;
12use Apie\Core\Other\DiscriminatorMapping;
13use Apie\Core\Utils\EntityUtils;
14use ReflectionClass;
15
16final class PolymorphicEntityStrategy implements StrategyInterface
17{
18    public static function supports(ReflectionClass $class): bool
19    {
20        return EntityUtils::isPolymorphicEntity($class);
21    }
22
23    /**
24     * @param ReflectionClass<PolymorphicEntityInterface> $class
25     */
26    public function __construct(private ReflectionClass $class)
27    {
28    }
29
30    public function getModificationMetadata(ApieContext $context): CompositeMetadata
31    {
32        $list = [];
33        
34        $class = $this->class;
35
36        while ($class) {
37            $method = $class->getMethod('getDiscriminatorMapping');
38            if (!$method->isAbstract() && $method->getDeclaringClass()->name === $class->name) {
39                /** @var DiscriminatorMapping $mapping */
40                $mapping = $method->invoke(null);
41                foreach ($mapping->getConfigs() as $config) {
42                    if ($method->getDeclaringClass()->name === $this->class->name || $config->getClassName() === $this->class->name) {
43                        $this->mergeChildClass($context, $config, $list, 'getModificationMetadata');
44                    }
45                }
46            }
47            $class = $class->getParentClass();
48        }
49
50        return new CompositeMetadata(new MetadataFieldHashmap($list), $this->class);
51    }
52
53    public function getCreationMetadata(ApieContext $context): CompositeMetadata
54    {
55        $list = [];
56        
57        $class = $this->class;
58
59        while ($class) {
60            $method = $class->getMethod('getDiscriminatorMapping');
61            if (!$method->isAbstract() && $method->getDeclaringClass()->name === $class->name) {
62                /** @var DiscriminatorMapping $mapping */
63                $mapping = $method->invoke(null);
64                $list[$mapping->getPropertyName()] = new DiscriminatorColumn($mapping);
65                foreach ($mapping->getConfigs() as $config) {
66                    if ($method->getDeclaringClass()->name === $this->class->name || $config->getClassName() === $this->class->name) {
67                        $this->mergeChildClass($context, $config, $list, 'getCreationMetadata');
68                    }
69                }
70            }
71            $class = $class->getParentClass();
72        }
73
74        return new CompositeMetadata(new MetadataFieldHashmap($list), $this->class);
75    }
76
77    public function getResultMetadata(ApieContext $context): CompositeMetadata
78    {
79        $list = [];
80        
81        $class = $this->class;
82
83        while ($class) {
84            $method = $class->getMethod('getDiscriminatorMapping');
85            if (!$method->isAbstract() && $method->getDeclaringClass()->name === $class->name) {
86                /** @var DiscriminatorMapping $mapping */
87                $mapping = $method->invoke(null);
88                $list[$mapping->getPropertyName()] = new DiscriminatorColumn($mapping);
89                foreach ($mapping->getConfigs() as $config) {
90                    if ($method->getDeclaringClass()->name === $this->class->name || $config->getClassName() === $this->class->name) {
91                        $this->mergeChildClass($context, $config, $list, 'getResultMetadata');
92                    }
93                }
94            }
95            $class = $class->getParentClass();
96        }
97
98        return new CompositeMetadata(new MetadataFieldHashmap($list), $this->class);
99    }
100
101    /**
102     * @param array<string, mixed> $list
103     */
104    private function mergeChildClass(
105        ApieContext $context,
106        DiscriminatorConfig $config,
107        array& $list,
108        string $method
109    ): void {
110        $refl = new ReflectionClass($config->getClassName());
111        $tmp = new RegularObjectStrategy($refl);
112        $mapping = $tmp->$method($context);
113        foreach ($mapping->getHashmap() as $propertyName => $declaration) {
114            if (isset($list[$propertyName])) {
115                $list[$propertyName] = new OptionalField($declaration, $list[$propertyName]);
116            } else {
117                $list[$propertyName] = new OptionalField($declaration);
118            }
119        }
120    }
121}